#include "CTableCreater.h"
#include "CAppendTable.h"
#include "CUpAppendTable.h"
#include "CUpdateTable.h"
#include "CAppendWithCounterTable.h"
#include "COverTable.h"

#include <nlohmann/json.hpp>
#include <sstream>
#include <fstream>
#include <boost/filesystem.hpp>



CTableCreater::CTableCreater(CTableManager* tableManager, CLogDatabaseMgr* dbManager):
	m_tableManager(tableManager),
	m_dbManager(dbManager)
{
}


CTableBasePtr CTableCreater::CreateTable(const std::string& tableJson, const std::string& defaultDb)
{
			try {
		// Parse the JSON configuration
		auto json = nlohmann::json::parse(tableJson);
		
		// Validate JSON structure
		if (!json.contains("logs") ||  !json["logs"].contains("tables")) {
			return nullptr;
		}
		
		// Extract database name - use defaultDb if not specified in JSON
		std::string databaseName;
		if (json["logs"].contains("database") && !json["logs"]["database"].is_null()) {
			databaseName = json["logs"]["database"];
		} else {
			databaseName = defaultDb;
		}
		
		// Get the database from the manager
		auto logDatabase = m_dbManager->GetLogDatabase(databaseName);
		if (!logDatabase) {
			// Database doesn't exist, create a new one
			logDatabase = std::make_shared<CLogDatabase>();
			logDatabase->setDatabaseFilePath(databaseName);
			m_dbManager->AddLogDatabase(databaseName, logDatabase);
		}
		
		// Process each table in the configuration
		for (const auto& tableConfig : json["logs"]["tables"]) {
			// Validate table configuration
			if (!tableConfig.contains("table") || !tableConfig.contains("table_type") || !tableConfig.contains("fields")) {
				continue; // Skip invalid table configurations
			}
			
			std::string tableName = tableConfig["table"];
			std::string tableType = tableConfig["table_type"];
			
			// Create table configuration
			auto tableConfigure = std::make_shared<CTableConfigure>();
			tableConfigure->setTableName(tableName);
			
			// Process fields
			for (const auto& fieldConfig : tableConfig["fields"]) {
				// Validate field configuration
				if (!fieldConfig.contains("name") || !fieldConfig.contains("type")) {
					continue; // Skip invalid field configurations
				}
				
				std::string fieldName = fieldConfig["name"];
				std::string fieldType = fieldConfig["type"];
				
				EFieldType type;
				int fieldSize = 0;
				
				if (fieldType == "int") {
					type = EFieldType::EFieldTypeInt;
				} else if (fieldType == "char") {
					type = EFieldType::EFieldTypeString;
					// Get size if specified
					if (fieldConfig.contains("size")) {
						fieldSize = fieldConfig["size"];
					}
				} else {
					// Unknown field type, skip or handle error
					continue;
				}
				
				// Create table field and add to configuration
				CTableField field(fieldName, type, fieldSize);
				tableConfigure->setTableField(field);
			}
			
			// Process configuration if present
			if (tableConfig.contains("config")) {
				const auto& config = tableConfig["config"];
				
				// Process key fields
				if (config.contains("uKeyField")) {
					std::string keyFieldStr = config["uKeyField"];
					std::vector<std::string> keyFields;
					
					// Split by '|' delimiter
					std::stringstream ss(keyFieldStr);
					std::string field;
					while (std::getline(ss, field, '|')) {
						keyFields.push_back(field);
					}
					tableConfigure->setKeyFields(keyFields);
				}
				
				// Process value fields
				if (config.contains("uValueField")) {
					std::string valueFieldStr = config["uValueField"];
					std::vector<std::string> valueFields;
					
					// Split by '|' delimiter
					std::stringstream ss(valueFieldStr);
					std::string field;
					while (std::getline(ss, field, '|')) {
						valueFields.push_back(field);
					}
					tableConfigure->setValueFields(valueFields);
				}
			}
			
			// Create the appropriate table based on type
			CTableBasePtr table;
			if (tableType == "append") {
				table = std::make_shared<CAppendTable>();
			}
			else if (tableType == "upappend") {
				table = std::make_shared<CUpAppendTable>();
			}
			else if (tableType == "update") {
				table = std::make_shared<CUpdateTable>();
			}
			else if (tableType == "count") {
				table = std::make_shared<CAppendWithCounterTable>();
			}
			else if (tableType == "over") {
				table = std::make_shared<COverTable>();
			}
			else {
				// Unknown table type
				return nullptr;
			}
			
			// Set the table configuration and database
			table->setTableConfigure(tableConfigure);
			table->setLogDatabase(logDatabase);
			
			// Add table to the manager
			m_tableManager->AddTable(tableName, table);
			
			// Return the created table (assuming we're creating one table at a time)
			return table;
		}
		
		return nullptr;
	} catch (const std::exception& e) {
		// Handle JSON parsing errors or other exceptions
		return nullptr;
	}
}

CTableBasePtr CTableCreater::CreateTable(const CXDTFile& xdtFile)
{
	try {
		
		std::string filePath = xdtFile.getPath();
		std::string fileName = xdtFile.getFileName();
		
		std::ifstream file(fileName);
		if (!file.is_open()) {
			return nullptr;
		}

		boost::filesystem::path pathObj(filePath);
		boost::filesystem::path fsfileName(filePath);
		fsfileName /= pathObj.filename();
		fsfileName.replace_extension(".xdb");
		std::stringstream buffer;
		buffer << file.rdbuf();
		std::string tableJson = buffer.str();
		file.close();
		
		return CreateTable(tableJson, fsfileName.string());
		
	} catch (const std::exception& e) {
		
		return nullptr;
	}
}
